/* 
 工具类函数

*/
function max(){
    // 先 声明一个变量 变量的值 是 默认第一个是最大 的
    var big = arguments[0]
    // 用这一个最大的和其他两个进行比较  
    for(var i = 1 ; i < arguments.length ; i++){
        // 如果有比他大的  我就让这个变量  = 这个值
        if(arguments[i] > big){
            big = arguments[i]
        }
    }

    return big
}

/* 
    获取范围之间的随机数
    @param a 范围下限
    @param b 范围上限
    @return 随机数
*/
function getRandom(a,b){
    return Math.floor(Math.random() * (b - a + 1) + a)
}

/* 
    获取随机颜色字符串
    @return 随机颜色字符串
*/
function getColor(){
    return 'rgb('+ getRandom(0,255) +', '+ getRandom(0,255) +', '+ getRandom(0,255) +')' 
}

/* 
    获取元素
    @param selector 选择器
    @param context 上下文区域
    @return 获取到的元素或者伪数组
*/
function my$(selector,context){
    // context 可以传 可以不传 
    context = context || document
    // 判断 传入的 selector 是 # 开头还是 . 开头 还是直接是一个标签
    if(selector.indexOf('#') === 0){
        return document.getElementById(selector.slice(1))
    }
    if(selector.slice(0,1) === '.'){
        return context.getElementsByClassName(selector.slice(1))
    }
    return context.getElementsByTagName(selector)
}

/* 
    获取/设置元素样式
    @param ele 要获取/设置的元素
    @param attr 要获取/设置的元素属性
    @param value 要设置的元素属性值
*/
function css(ele,attr,value){
    if(!value){
        return window.getComputedStyle ? window.getComputedStyle(ele)[attr] : ele.currentStyle[attr]
    }
    ele.style[attr] = value
    return 123
}

/* 
    添加事件监听
    @param ele 要绑定事件的元素
    @param type 事件类型
    @param fn 事件处理函数
*/
function on(ele,type,fn){
    if(ele.addEventListener){
        if(type.indexOf('on') === 0){
            type = type.slice(2)
        }
        ele.addEventListener(type,fn)
    }else{
        if(type.indexOf('on') !== 0){
            type = 'on' + type
        }
        ele.attachEvent(type,fn)
    }

}

/* 
    解绑事件
*/
function off(ele,type,fn){
    if(ele.removeEventListener){
        if(type.indexOf('on') === 0){
            type = type.slice(2)
        }
        ele.removeEventListener(type,fn)
    }else{
        if(type.indexOf('on') !== 0){
            type = 'on' + type
        }
        ele.dettachEvent(type,fn)
    }
}

/* 
    获取元素 width + padding 

*/
function inWidth(ele){
    if(css(ele,"display") === 'none'){
        return parseFloat(css(ele,'width')) + parseFloat(css(ele,'paddingLeft')) + parseFloat(css(ele,'paddingRight'))
    }
    return ele.clientWidth
}
function inHeight(ele){
    if(css(ele,"display") === 'none'){
        return parseFloat(css(ele,'height')) + parseFloat(css(ele,'paddingTop')) + parseFloat(css(ele,'paddingBottom'))
    }
    return ele.clientHeight
}
// width + padding + border
function outWidth(ele){
    if(css(ele,"display") === 'none'){
        return parseFloat(css(ele,'width')) + parseFloat(css(ele,'paddingLeft')) + parseFloat(css(ele,'paddingRight')) + parseFloat(css(ele,'borderLeftWidth')) + parseFloat(css(ele,'borderRightWidth'))
    }
    return ele.offsetWidth
}
function outHeight(ele){
    if(css(ele,"display") === 'none'){
        return parseFloat(css(ele,'height')) + parseFloat(css(ele,'paddingTop')) + parseFloat(css(ele,'paddingBottom')) + parseFloat(css(ele,'borderTopWidth')) + parseFloat(css(ele,'borderBottomWidth'))
    }
    return ele.offsetWidth
}

function animate(ele, options, duration,callback) {
    // 每一次点击 先把元素身上的 timer 属性 清除了
    clearInterval(ele.timer)
    // start 是用来 装初始值  range 是每一个属性的区间范围
    const start = {}, range = {}
    for (let key in options) {
        start[key] = parseFloat(css(ele, key))
        range[key] = options[key] - start[key]
    }
    //先保存一个 调用函数时候 的时间戳 
    const startTime = +new Date()
    // 在元素身上挂载了一个属性 
    ele.timer = setInterval(() => {
        let nowTime = +new Date()
        // 时间差
        let timeDifference = Math.min(nowTime - startTime,duration)
        // 如果时间差 < 我规定的时间 那就用时间差
        // 如果时间差 > 我规定的时间 那就用我规定的时间
        // 设置元素运动的值 
        for (let attr in options) {
            let result = range[attr] / duration * timeDifference + start[attr]
            // 添加一个 透明判断
            result = attr === 'opacity' ? result : result + 'px'
            ele.style[attr] = result
        }
        //  判断清除定时器
        if (timeDifference === duration) {
            clearInterval(ele.timer)
            //这个地方代表已经执行完毕 所以可以调用 回调函数
            // 这个回调函数是可选参数 
            callback && callback()
        }
    }, 10)

}


function fadeOut(ele,duration,fn){
    css(ele,'display','block')
    css(ele,'opacity','1')
    animate(ele,{opacity:0},duration,fn)
}

function fadeIn(ele,duration,fn){
    css(ele,'display','block')
    css(ele,'opacity','0')
    animate(ele,{opacity:1},duration,fn)
}

/* 
    @param key 要设置的属性
    @param value 要设置的属性值
    @param options 配置项(expires:有效时间,path:目录)

*/
function setCookie(key,value,options={
    expires:new Date(),
    path:'/'
}){
    document.cookie = `${key}=${encodeURIComponent(value)};expires=${options.expires};path=${options.path}`
}

/* 
    @param str 要获取的 cookie 的属性
    @return 要获取的 cookie 的属性值
*/
function getCookie(str){
    const cookie = document.cookie         
    const obj = {}
    const arr = cookie.split('; ')
    arr.forEach(item=>{
        const subArr = item.split('=')
        obj[subArr[0]] = decodeURIComponent(subArr[1])
    })
    return obj[str]
}



// 如果传了 参数 那就是吧整个 options 全部替换
function ajax(options){
    // console.log(options)
    // 1、判断 url 有没有传入 
    if(!options.url){
        // 手动抛出错误
        // 进入这个 if 判断 代表没有传入 url
        throw new Error('url 是必传项')
    }
    // 设置默认值
    let defaultInfo = {
        type:'GET',
        data:'',
        dataType:'string',
        // dataType:'json'   // 期望后端给我返回的数据是 json 格式
        success(){ console.log('你还没有传入回调函数') },
        error(){ console.log('你还没有传入回调函数') }
    }
    // 把传入的参数 放到 defaultInfo 里面去
    for(let key in options){
        defaultInfo[key] = options[key]
    }
    // console.log(defaultInfo)
    // 2、参数 处理 
    if(!(defaultInfo.type.toUpperCase() === 'POST' || defaultInfo.type.toUpperCase() === 'GET')){
        throw new Error('目前只支持 post or get 请求 请期待后续更新')
    }

    // 3、发送请求 
    let xhr
    try{
        xhr = new XMLHttpRequest()
    }catch(err){
        xhr = new ActiveXObject('Microsoft.XMLHTTP')
    }
    // 判断是 get 还是 post 
    defaultInfo.url = defaultInfo.type.toUpperCase() === 'GET' ? defaultInfo.url + '?' + defaultInfo.data : defaultInfo.url

    // console.log(defaultInfo)
    xhr.open(defaultInfo.type,defaultInfo.url)

    // 判断是 get 还是 post 
    if(defaultInfo.type.toUpperCase() === 'GET'){
        xhr.send()
    }else{
        xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
        xhr.send(defaultInfo.data)
    }

    xhr.onreadystatechange = function(){
        if(xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)){
            // defaultInfo.success()
            // 判断 dataType 如果传的事 json 那么先把数据转换一下再 传过去
            defaultInfo.dataType === 'json' ? defaultInfo.success(JSON.parse(xhr.responseText)) : defaultInfo.success(xhr.responseText)
        }else if(xhr.readyState === 4 && !(/^2\d{2}$/.test(xhr.status))){
            defaultInfo.error(xhr.responseText)
        }
    }

}

// const p1 = ajax()
// p1.then()


function fetch1(options){
    return new Promise((resolve, reject) => {
       ajax({
           ...options,
           success(res){
            resolve(res)
           },
           error(error){
               reject(error)
           }
       })
    })
}

